package edu.toronto.whimper.MapObjects;

import java.util.ArrayList;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

@SuppressWarnings("rawtypes")
public class MapItemizedOverlay extends ItemizedOverlay{

	private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
	private int mOverlaysSize = -1;
	private Context mContext;
	//public static Utils.MarkerColors color = Utils.MarkerColors.GREEN;
	private int mapSmallRegionBlocksSize = 50;
	private long lastMapDrawTime = -1, minimumDelayBetweenDrawMaps = 10000;
	private GeoPoint lastMapDrawLocation = new GeoPoint(1, 1);
	private float minimumDistanceForReDrawMapOverlay = 100;
	private Bitmap estimatedNoiseOverlayBitmap;
	private int estimatedNoiseMapWidth = 320, estimatedNoiseMapHeight = 480;
	private int lastMapDrawLevel = -1;
	private int colorTransparencyLevel = 128;
		
	public MapItemizedOverlay(Drawable marker, Context context) {
		
		super(boundCenterBottom(marker));
		 mContext = context;
	}
		
	public void addOverlay(OverlayItem overlay) {
	    mOverlays.add(overlay);
	    mOverlaysSize = mOverlays.size();
	    populate();
	}
	
	@Override
	protected OverlayItem createItem(int i) {
		return mOverlays.get(i);
	}

	@Override
	public int size() {
		return mOverlaysSize;
	}
	
	@Override
	protected boolean onTap(int index) {
	  OverlayItem item = mOverlays.get(index);
	  AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
	  dialog.setTitle(item.getTitle());
	  dialog.setMessage(item.getSnippet());	
	  dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {  
		   public void onClick(DialogInterface dialog, int id) {  
		     dialog.dismiss(); 
		}  
		});
	  dialog.show();
	  
	  return true;
	}
	/*private Drawable getMarker()
	{
		switch(this.color){
	           case BROWN: return mContext.getResources().getDrawable(R.drawable.brown_dot);
	           case RED: return mContext.getResources().getDrawable(R.drawable.red_dot);
	           case YELLOW: return mContext.getResources().getDrawable(R.drawable.yellow_dot);
	           case GREEN: return mContext.getResources().getDrawable(R.drawable.green_dot);
	           case BLUE: return mContext.getResources().getDrawable(R.drawable.blue_dot);
	           case PURPLE: return mContext.getResources().getDrawable(R.drawable.purple_dot);
	           default: return mContext.getResources().getDrawable(R.drawable.green_dot);
	        }
	  }*/
	
	public void draw(Canvas canvas, MapView mapv, boolean shadow)
	{
		Projection mapProjection = mapv.getProjection();
        
        Point generatedNoiseMapStartPoint = new Point();
        
        
        
        if (lastMapDrawLevel != mapv.getZoomLevel() )
        {
            lastMapDrawLocation = mapProjection.fromPixels(-estimatedNoiseMapWidth, -estimatedNoiseMapHeight);
            lastMapDrawLevel = mapv.getZoomLevel();
            updateNoiseEstimationMap(mapv);
        }
        
        mapProjection.toPixels(lastMapDrawLocation, generatedNoiseMapStartPoint);

        if ((generatedNoiseMapStartPoint.x > 0) ||
        		(generatedNoiseMapStartPoint.y > 0) ||
        		(generatedNoiseMapStartPoint.x + 2 * estimatedNoiseMapWidth < 0) ||
        		(generatedNoiseMapStartPoint.y + 2 * estimatedNoiseMapHeight < 0))
        {
            lastMapDrawLocation = mapProjection.fromPixels(-estimatedNoiseMapWidth, -estimatedNoiseMapHeight);
            lastMapDrawLevel = mapv.getZoomLevel();
            updateNoiseEstimationMap(mapv);
        }
        
        super.draw(canvas, mapv, shadow);
        
        //Point generatedNoiseMapStartPoint = new Point();
        
        mapProjection.toPixels(lastMapDrawLocation, generatedNoiseMapStartPoint);
        
        canvas.drawBitmap(estimatedNoiseOverlayBitmap, generatedNoiseMapStartPoint.x, generatedNoiseMapStartPoint.y, null);


        
    }
	
	private float estimateNoiseLevel(GeoPoint location)
	{
		GeoPoint basePoint = new GeoPoint(43659221, -79396477);
		
		float distance = distanceBetweenGeoPoints(location, basePoint);
		
		if (distance > 1000)
		{
			distance = 1000;
		}
		
		float estimatedNoise;
		
		estimatedNoise = 90 - ( 50 * distance / 1000);
		return estimatedNoise;
	}
	
	private float distanceBetweenGeoPoints(GeoPoint firstPoint, GeoPoint secondPoint)
	{
		float [] distanceResult = new float[2];
		
		android.location.Location.distanceBetween(firstPoint.getLatitudeE6()/1000000.0, firstPoint.getLongitudeE6()/1000000.0, 
				secondPoint.getLatitudeE6()/1000000.0, secondPoint.getLongitudeE6()/1000000.0, distanceResult);
		
		return distanceResult[0];
	}
	
	private void updateNoiseEstimationMap(MapView mapv)
	{
        Paint myPaint = new Paint();
        Projection mapProjection = mapv.getProjection();
        GeoPoint currentBlockLocation;
        
        estimatedNoiseOverlayBitmap = Bitmap.createBitmap(estimatedNoiseMapWidth*3, estimatedNoiseMapHeight*3, Bitmap.Config.ARGB_8888);
        
        Canvas bitmapCanvas = new Canvas(estimatedNoiseOverlayBitmap);
        
        float estimatedNoise;
        
        myPaint.setARGB(128, 128, 128, 128);
        
        for (int i = 0 ; i < estimatedNoiseOverlayBitmap.getWidth() ; i+=mapSmallRegionBlocksSize)
        {
        	for (int j = 0 ; j <  estimatedNoiseOverlayBitmap.getHeight() ; j+=mapSmallRegionBlocksSize)
        	{
        		currentBlockLocation = mapProjection.fromPixels(i+mapSmallRegionBlocksSize/2 - estimatedNoiseMapWidth, j+mapSmallRegionBlocksSize/2 - estimatedNoiseMapHeight);
        		estimatedNoise = estimateNoiseLevel(currentBlockLocation);
        		
        		//myPaint.setARGB(128, (int)(280-estimatedNoise), 0, 0);
        		//myPaint.setColor(Color.argb(128, (int)(200-estimatedNoise), 0, 0));
        		myPaint.setColor(convertNoiseToColor(estimatedNoise));
        		bitmapCanvas.drawRect(i, j, i+mapSmallRegionBlocksSize, j+mapSmallRegionBlocksSize, myPaint);
        	}
        }

		
	}
	
	private int convertNoiseToColor(float inputNoiseValue)
	{
		// Noise color mapping method:
		// 35 db is set as Cyan (25,225,225)
		// 35-55 db are maped to Cyan-Green range
		// 55 db is set as Green (25,225,25)
		// 55-75 db are mapped to Green-Amber range
		// 75 db is set as Amber (225,225,25)
		// 75-95 db are mapped to Amber-Red range
		// 95 db is set as Red (225,25,25)
		
		float noiseValue = inputNoiseValue;
		
		// Be sure that it is in the range of 35-96
		if (noiseValue < 35)
		{
			noiseValue = 35;
		}
		if (noiseValue > 95)
		{
			noiseValue = 95;
		}
		
		if (noiseValue < 55)
		{
			// The 35-55 range
			return Color.argb(colorTransparencyLevel, 25, 225, (int) (225 - 10 * (noiseValue-35)));
		}
		if (noiseValue < 75)
		{
			// The 55-75 range
			return Color.argb(colorTransparencyLevel, (int) (25 + 10 * (noiseValue-55)), 225, 25);
		}
		// The 75-95 range
		return Color.argb(colorTransparencyLevel, 225, (int) (225 - 10 * (noiseValue-75)), 25);
	}

}
